#include <stdlib.h>
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <avr/pgmspace.h>

#include "uart.h"
#include "usbn2mc.h"
#define F_CPU 16000000U
#include <util/delay.h>

#include "../usbn2mc/main/usbnapi.h"
#include "usbn2mc.h"

//#include "avrlib/timer128.h"
//
#include "common.h"
#include "protocol.h"

#include "io.h"
#include "adc.h"
#include "i2c.h"
#include "spi.h"

volatile int togl=0; 

void USBMessageSent(void);
void USBAskStatus(void);
void USBGetLog(void);



void
delay_250ms (void)
{
  uint8_t i;

  for (i = 0; i < 25; i++)
    _delay_ms (10);
}


SIGNAL(SIG_INTERRUPT4)
{
  USBNInterrupt();
}

SIGNAL (SIG_UART0_RECV)
{

}

/* internal timer */
SIGNAL(SIG_OVERFLOW0)
{
  //PORTB = 0xFF;
  //PORTB = 0x00;

  common_scheduler();

  TCNT0 = octopus.latency_timer;
}

/* called after data where send to pc */
void USBMessageSent(void)
{
  //PORTD ^=  (1<<PD7);
  //CommandAnswer(2);
}

/* called after data where send to pc */
void USBAskStatus(void)
{

}

/* called after data where send to pc */
void USBGetLog(void)
{

}

/* is called when received data from pc */
void USBMessageIn(char *buf)
{
  octopus.togl = 0;
  STATUS_LED_on;
  
  int check = ((int)buf[0]>>4) & 0x0F;
  STATUS_LED_off;

  switch(check){
    case 0:
      common_parser(buf);
    break;
    case 1:
      io_parser(buf);
    break;
    case 2:
      adc_parser(buf);
    break;
    case 3:
      i2c_parser(buf);
    break;
    case 4:
      spi_parser(buf);
    break;


    default:
      answer[0]=buf[0];
      answer[1]=RSP_UNKOWN_CMD;
      answer[2]=0;
      CommandAnswer(3);
  }

}


void CommandAnswer(int length)
{
  int i;

  USBNWrite(FIFOTXC1, FLUSH);
  for(i = 0; i < length; i++)
    USBNWrite(TXD1, answer[i]);

  /* control togl bit */
  if(octopus.togl == 1) {
    USBNWrite(FIFOTXC1, TX_LAST+TX_EN+TX_TOGL);
    octopus.togl = 0;
  } else {
    USBNWrite(FIFOTXC1, TX_LAST+TX_EN);
    octopus.togl = 1;
  }
}

int main (void)
{    
  //DDRD=0xFC;
  //PORTD=0xFC;

  DDRB = 0xFF;
  PORTB = 0xFF;
 
  
  int interf;         
  int conf;

  STATUS_LED_off;

  UARTInit();
  USBNInit();                                      // activate usb kernel

  // setup your device
  USBNDeviceVendorID(0x1781);     // 0x0400 is the number from national
  USBNDeviceProductID(0x0c65);    // add your product id
  USBNDeviceBCDDevice(0x0001);  // you can use it as version e.g. version 1.02 

  char lang[]={0x09,0x04,0x00};
  _USBNAddStringDescriptor(lang); // language descriptor


  // Achtung!!! Deskriptor muessen immer 8*x gross sein! (Fehler im Stack)
  USBNDeviceManufacture("EmbeddedProjects");
  USBNDeviceProduct("OctopusUSB Interface Converter and I/O Extension");
  USBNDeviceSerialNumber("20081108");


  conf = USBNAddConfiguration();

  USBNConfigurationPower(conf,100);

  interf = USBNAddInterface(conf,0);
  USBNAlternateSetting(conf,interf,0);

  /* communication */
  USBNAddInEndpoint(conf,interf,1,0x01,BULK,64,0,USBMessageSent);
  USBNAddOutEndpoint(conf,interf,1,0x01,BULK,64,0,&USBMessageIn);


  /* state */
  USBNAddInEndpoint(conf,interf,1,0x02,INTR,64,1,USBAskStatus);
  
  /* logging */
  USBNAddInEndpoint(conf,interf,1,0x03,BULK,64,1,USBGetLog);

  USBNInitMC();

  octopus.togl = 0;
  // start usb chip
  USBNStart();
  
  // initialize the timer system
  common_latency_timer_init();

  //int i,ms=500;
  //DDRD = 0xFF;
  //PORTD = 0x00;
  //PORTD = 0xff;
  
  //DDRB = (1 << DDB7);
  //PORTB |= (1<<PB7);

  // hello world led pattern
  DDRC = 0xFF;
  PORTC = 0xAA;
  delay_250ms();
  PORTC = 0xD5;
  delay_250ms();
  PORTC = 0x80;
  //PORTB &= ~(1<<PB7); 


  while(1);

  return 0;
}




